#include "TypeDialog.h"
#include "DiagramScene.h"
#include "TypeManager.h"
#include "TypeVariableEntry.h"
#include "TypeEntryItem.h"
#include "TypeEntryFrameItem.h"
#include "NodeItem.h"
#include "WOP_Entry.h"
#include "TypeVariablePanel.h"
#include "MappingEngine.h"
#include <QGraphicsView>
#include <QGraphicsRectItem>
#include <QPushButton>
#include <QCheckBox>
#include <QFileDialog>
#include <QMessageBox>
#include <QCloseEvent>
#include <QAction>
#include <QDateTime>
#include <cassert>

TypeDialog::TypeDialog( QWidget * parent )
	: AbstractMappingWindow( parent )
{	
	init();
	_currentEntry = NULL;
	_foreachRect = NULL;
	this->_mapping = NULL;
	this->contextMenu_ = new QMenu( this );
	this->currentMenuEntry_ = nullptr;
	this->currentOutPort_ = nullptr;
	this->finished_ = false;
	
	QAction * addTM = new QAction( QObject::tr( "Add Mapping For This Type" ), this->contextMenu_ );
	this->connect( addTM, SIGNAL( triggered() ), SLOT( onAddTM() ) );
	this->contextMenu_->addAction( addTM );
}

TypeDialog::~TypeDialog()
{

}

void TypeDialog::setCurrentEntry( WOP_Entry* entry )
{
	this->_currentScene->clear();
	this->_currentManager->reset();
	this->_foreachRect = NULL;

	// reset existing mapping tree
	this->_mapping = nullptr;
	this->_currentEntry = entry;
	
	if ( this->_currentEntry->getTypeStr() == "array" ){
		this->createForeachRect();
	}
	this->initVMButtonTab();
	this->_currentScene->addInputPaneltoCanvas();
	this->initEntry();				// 初始化變數Entry的外觀與位置
}

WOP_Entry* TypeDialog::currentEntry()
{
	return this->_currentEntry;
}

void TypeDialog::createSubTab( std::string tabName, WOP_Entry* entry )
{
	assert(_currentManager);
	_currentManager->unfoldEntry(entry);
	this->setCurrentEntry(entry);
	createNewTab( tabName );		// 建立新的Tab

	// 把除了新產生的tab之外的其他tab都block(disable)住，以免使用者在拉mapping的時候產生一些衝突狀況
	for ( int i = 0; i < ui.mappingTreeTabWidget->count()-1; ++i )
	{
		ui.mappingTreeTabWidget->setTabEnabled(i, false);
	}

}

// 跳出 File Dialog讓使用者儲存 mds 檔案
void TypeDialog::saveMDS()
{
	QString fileName = QFileDialog::getSaveFileName(
		this, 
		tr("Save File"),
		"mds/", 
		tr("MDS files (*.mds)"));

	saveMDS(fileName);
}

void TypeDialog::saveMDS( QString fileName )
{
	if ( !fileName.isEmpty() ){
		this->_currentManager->setSaveFileName(fileName);
		this->_currentManager->saveMapping(_currentManager->getSaveFileName(),_currentEntry);
	}
}

// 跳出 file dialog讓使用者選擇要讀入的mds檔案
// 並依照讀入的mds 檔案建立及設定 xMappingTree
// 最後關閉 mapping dialog 視窗
void TypeDialog::loadMDS()
{	
	QString MDSfile = QFileDialog::getOpenFileName(
		NULL,
		"Select MDS file to load in DIVA",
		"mds/",
		tr("MDS files (*.mds)"));

	loadMDS(MDSfile);

}

void TypeDialog::loadMDS( QString MDSfile)
{
	if ( !MDSfile.isEmpty() ){
		xMappingTree* xmt = this->_currentManager->createXMTFromMDS(MDSfile, _currentEntry);
		this->_mapping = xmt;

		// 將load進來的mds存進MDString裡
		pair<string,string> mdsPair = MappingEngine::getInstance()->readMDSfile(MDSfile.toStdString());
		MappingEngine::getInstance()->addMDString(mdsPair.first,mdsPair.second);
		this->close();
	}
}


void TypeDialog::clickApply()
{

	// TODO: 檢查mappingTree是否合法，判斷各類不合法的情形並且提醒使用者
	if (_currentManager->validateAllNodes() == false ){
		QMessageBox::critical( this, tr("Mapping Error"), tr("Some arithmetic have no value!"));
		return;
	} 

	if ( _currentManager->checkRootNumberValidate() == false ){
		QMessageBox::critical( this, tr("Mapping Error"), tr("Type mapping must connect to a varname!"));
		return;
	}

	// 假如是 generic 的 array 所拉的 mapping node，則先存成 mds 再 load
	if ( _currentEntry->getTypeStr() == "array" && this->getForeachRect()->scenePos().x()>=0 )
	{
		QString tempFileName ="~temp";
		tempFileName.append(QDateTime::currentDateTime().toString("ddMMhhmmsszzz"));
		tempFileName.append(".mds");
		this->saveMDS(tempFileName);
		this->loadMDS(tempFileName);
		QFile::remove(tempFileName);
		return;
	}

	_currentManager->deleteEmptyPort();			 //清除空的port vmcollect及wop collector
	this->_mapping = _currentManager->getMappingTree();	// 從NodeManager取得mapping tree

//	QString filePath = QString( "DES/%1.des" ).arg( this->_currentEntry->getVarType().c_str() );
//	this->_currentManager->saveVMtoDESFiles( filePath, "tm", "" );

	this->_currentManager->addMDSString( this->_currentEntry );

	this->close();
	this->finished_ = true;
	emit this->finished();
}

// 當視窗關掉之前要處理的事情寫在這個function裡面，mapping dailog關掉時上層QDialog也關掉
void TypeDialog::closeEvent( QCloseEvent * event )
{
	event->accept();

	// 將上層QDialog(mapping dialog的parent)關掉
	this->finished_ = false;
	emit this->finished();
//	QDialog *dialog = dynamic_cast<QDialog*>(this->parent());
//	assert(dialog);
//	dialog->accept();

	//this->setParent(0);
}

void TypeDialog::initMenuBar()
{
	ui.menuFile->clear();
	_saveMDSFile = new QAction("Save MDS File", ui.menuBar);
	_loadMDSFile = new QAction("Load MDS File",ui.menuBar);

	connect( _saveMDSFile, SIGNAL(triggered()), this, SLOT(saveMDS()));
	connect( _loadMDSFile, SIGNAL(triggered()), this, SLOT(loadMDS()));

	ui.menuFile->addAction(_saveMDSFile);
	ui.menuFile->addAction(_loadMDSFile);
}

void TypeDialog::initEntry()
{
	using namespace std;
	_currentScene->setEntry(this->_currentEntry);
	_currentManager->initVariableEntry(_currentEntry);

	vector<xMappingNode*> entryList = _currentManager->getEntry()->getEntryList();
	vector<WOP_Entry*> wopList = _currentManager->getEntry()->getWopList();

	int wopNumber = _currentManager->getEntry()->getWopList().size();

	// 如果entryList裡面只有一個entry，就直接把這個entry放到graphicsScene上面
	if ( entryList.size() == 1 ){
		TypeEntryItem* entry = _currentManager->createEntryItem( _currentManager->getEntry()->getEntryNameAT(0), _currentManager->getEntry()->getEntryTypeAT(0), entryList.at(0), wopList.at(0));
		_currentManager->getVariablePanel()->insertItem(entry);
		entry->unfold();
	} 
	// 如果entryList裡面不只一個entry，就表示他們是同一個array裡面的elements或者是同一個class的members
	// 這時候不直接將entryList裡面的entries放到graphicsScene上面，而是新增一個EntryNodeFrame
	// 由這個EntryNodeFrame來統整這些屬於同一個array或class的entries
	else if ( entryList.size() > 1 ){

		WOP_Entry* entry = this ->currentEntry();
		_currentManager->createEntryFrameItem( entry ,entryList, _currentScene, _currentManager->getVariablePanel());
	} 
	//如果entryList裡面沒有entry，表示有error
	else {
		assert(false);
	}
}

void TypeDialog::createOtherWidget()
{
	QVBoxLayout *layout = dynamic_cast<QVBoxLayout*> (ui.mappingTreeTabWidget->widget(0)->layout());
	assert(layout);

	// new apply button
	QPushButton* applyButton = new QPushButton("Apply");
	applyButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
	applyButton->setObjectName("applyButton");
	connect( applyButton, SIGNAL(clicked()), this, SLOT(clickApply()) );

	// new apply to all checkbox
	QCheckBox* applyAllCheckBox = new QCheckBox("Apply to All");
	applyAllCheckBox->setVisible( false );

	QHBoxLayout *buttonLayout = new QHBoxLayout;
	buttonLayout->setContentsMargins(9,9,9,9);
	buttonLayout->addWidget(applyAllCheckBox);
	buttonLayout->addStretch();
	buttonLayout->addWidget(applyButton);
	

	layout->addLayout(buttonLayout);
}

void TypeDialog::initCanvas()
{
	createNewTab("Main");
	
}

QGraphicsRectItem* TypeDialog::getForeachRect()
{
	return this->_foreachRect;
}

void TypeDialog::createForeachRect()
{
	_foreachRect = new QGraphicsRectItem(0, 0, 600, SCENE_HEIGHT);
	_foreachRect->setBrush(QColor("#444444"));
	_currentScene->addItem(_foreachRect);
	_foreachRect->setPos(0,0);
}

AbstractManager* TypeDialog::initManager()
{
	// new manager
	TypeManager* manager = new TypeManager(this);
	this->_currentManager = manager;
	connect( _currentManager, SIGNAL(itemSelected(NodeItem*)), this, SLOT(showAttribute(NodeItem* )));
	connect( _currentManager, SIGNAL(itemDeSelected()), this, SLOT(cleanTreeWidget()));
	return manager;
}

xMappingTree * TypeDialog::getMappingTree() const {
	return this->_mapping;
}

void TypeDialog::onAddTM() {
	TypeDialog * dialog = new TypeDialog( this );
	dialog->setCurrentEntry( this->currentMenuEntry_ );
	QEventLoop wait;
	wait.connect( dialog, SIGNAL( finished() ), SLOT( quit() ) );
	wait.connect( dialog, SIGNAL( canceled() ), SLOT( quit() ) );
	dialog->show();
	this->hide();
	wait.exec();
	dialog->deleteLater();
	this->show();

	/*
	auto ph = this->addMappingNode( this->currentMenuEntry_ );
	auto inPort = ph->getInPortByName( "object" );
	auto link = this->_currentManager->createLine( inPort, this->currentOutPort_ );
	this->_currentScene->addItem( link );
	*/

	this->currentMenuEntry_ = nullptr;
	this->currentOutPort_ = nullptr;
}

void TypeDialog::onContextMenu( WOP_Entry * entry, NodeOutPort * outPort ) {
	this->currentMenuEntry_ = entry;
	this->currentOutPort_ = outPort;
	this->contextMenu_->popup( QCursor::pos() );
}

bool TypeDialog::isFinished() const {
	return this->finished_;
}

/*
NodeItem * TypeDialog::addMappingNode( WOP_Entry * en ) {
	// 這裡不能使用QString::toStdString()，mappingNodeName會無法正確轉成std::string
	NodeItem *mappingNode = this->_currentManager->createNode( en );
	this->_currentScene->addItem(mappingNode);

	// 將mapping node放在畫布的中央
	// TODO: 這裡還沒解決重疊的問題
	mappingNode->setPos(_currentView->viewport()->size().width()/2, _currentView->viewport()->size().height()/2 - mappingNode->height());	

	return mappingNode;
}
*/
